import type { PlasmoCSConfig } from "plasmo"

export const config: PlasmoCSConfig = {
    matches: ["https://channels.weixin.qq.com/platform/statistic/dashboardV4*"],
    all_frames: true,
    world: "MAIN",
    run_at: "document_start"
}

const WxLiveInterceptEventName = "wxLiveHijackData"


/**
 * 发送拦截数据事件信息
 */
function sendInterceptorData(interceptorData: {
    type: string;
    url: string;
    method: string;
    response: any;
}) {
    const _sender = (window.parent || window) as Window & typeof global
    _sender.dispatchEvent(
        new CustomEvent(WxLiveInterceptEventName, {
            detail: interceptorData
        })
    )
}


/**
 * 监控iframe内的网络请求方法
 * @param iframe 要监控的目标iframe元素
 */
function monitorIframeMethods(iframe: HTMLIFrameElement) {
    try {
        const iframeWindow = iframe.contentWindow as (Window & {
            // 类型断言确保包含XMLHttpRequest属性
            XMLHttpRequest: typeof XMLHttpRequest;
            fetch: typeof fetch;
        }) | null;

        if (!iframeWindow) {
            console.log("[监控] 无法访问iframe窗口（CORS/沙箱限制）");
            return;
        }

        // 劫持iframe中的fetch方法
        hijackFetchMethod(iframeWindow);
        // 劫持iframe中的XMLHttpRequest方法
        hijackXhrMethod(iframeWindow);

    } catch (error) {
        console.error("[监控] iframe监控失败:", error);
    }
}

/**
 * 劫持fetch方法并添加增强日志
 * @param targetWindow 目标窗口对象
 */
function hijackFetchMethod(targetWindow: Window & { fetch: typeof fetch }) {
    const original = targetWindow.fetch;
    targetWindow.fetch = async (...args) => {
        const [input, init] = args;
        const url = typeof input === "string" ? input : input.url;
        const method = init?.method || "GET";

        // 发起原始请求
        const response = await original.apply(targetWindow, args);

        try {
            // 克隆响应以避免影响原始数据流
            const clonedResponse = response.clone();
            const responseData = await parseResponse(clonedResponse);

            // 结构化输出请求和响应信息
            const interceptRes = {
                type: "fetch",
                url: url,
                method: method,
                response: responseData
            }
            sendInterceptorData(interceptRes); // 发送拦截数据到事件
            // console.log("[Fetch] 响应结果:", interceptRes);
        } catch (error) {
            console.error("解析响应失败:", error);
        }

        return response;
    };
}

/**
 * 劫持XMLHttpRequest方法并添加增强日志
 * @param targetWindow 目标窗口对象
 */
function hijackXhrMethod(targetWindow: Window & { XMLHttpRequest: typeof XMLHttpRequest }) {
    const OriginalXHR = targetWindow.XMLHttpRequest;

    // 创建代理类
    targetWindow.XMLHttpRequest = class extends OriginalXHR {
        private _url: string = "";
        private _method: string = "GET";

        /**
         * 重写open方法记录请求信息
         */
        open(method: string, url: string) {
            this._method = method;
            this._url = url;
            super.open(method, url);
        }

        /**
         * 重写send方法添加日志拦截
         */
        send(body?: Document | XMLHttpRequestBodyInit | null) {
            // 添加响应监听
            this.addEventListener("readystatechange", () => {
                if (this.readyState === this.DONE) {
                    try {
                        // 尝试解析响应数据
                        const interceptRes = {
                            type: "xhr",
                            url: this._url,
                            method: this._method,
                            response: this._parseResponse()
                        }
                        sendInterceptorData(interceptRes); // 发送拦截数据到后台
                        // console.log("[XHR] 响应结果:", interceptRes);
                    } catch (error) {
                        console.error("记录XHR响应失败:", error);
                    }
                }
            });

            // 添加错误处理
            this.addEventListener("error", () => {
                console.error(`[XHR] 请求失败: ${this._method} ${this._url}`);
            });

            super.send(body);
        }

        /**
         * 解析响应数据
         */
        private _parseResponse(): any {
            try {
                return typeof this.response === "string" ?
                    tryParseJson(this.response) :
                    this.response;
            } catch {
                return this.responseText;
            }
        }
    };
}

/**
 * 尝试解析响应内容
 * @param response 响应对象
 */
async function parseResponse(response: Response) {
    const contentType = response.headers.get("content-type") || "";
    if (contentType.includes("application/json")) {
        return await response.json();
    }
    return await response.text();
}

/**
 * 尝试解析JSON字符串
 * @param str 要解析的字符串
 */
function tryParseJson(str: string): any {
    try {
        return JSON.parse(str);
    } catch {
        return str;
    }
}


/**
 * 使用MutationObserver监控iframe挂载
 */
function observeIframeMount() {
    // 确保document.body存在
    const observeTarget = document.body || document.documentElement

    const observer = new MutationObserver((mutations) => {
        mutations.forEach((mutation) => {
            mutation.addedNodes.forEach((node) => {
                if (node.nodeName === "IFRAME") {
                    const iframe = node as HTMLIFrameElement
                    if (iframe.name === "statistic") {
                        console.log("[Observer] Target iframe mounted")

                        monitorIframeMethods(iframe)

                        iframe.addEventListener("load", () => {
                            console.log("[Observer] Iframe loaded")
                            monitorIframeMethods(iframe)
                        })
                    }
                }
            })
        })
    })

    observer.observe(observeTarget, {
        childList: true,
        subtree: true
    })

    // 检查是否已经存在目标iframe
    const existingIframe = document.querySelector('iframe[name="statistic"]') as HTMLIFrameElement | null
    if (existingIframe) {
        console.log("[Observer] Existing iframe detected")
        monitorIframeMethods(existingIframe)
    }
}

// 确保DOM加载完成后执行
if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", observeIframeMount)
} else {
    observeIframeMount()
}

export default () => null
